package com.zxisl.handler;

import com.google.gson.Gson;
import com.zxisl.bean.Mail;
import com.zxisl.javamail.IMAP2Store;
import com.zxisl.util.*;
import org.apache.commons.io.FileUtils;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.log4j.Logger;
import org.elasticsearch.client.transport.TransportClient;
import org.jsoup.Jsoup;

import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.*;

import static com.zxisl.util.MailUtil.*;
import static java.util.Arrays.copyOf;

/**
 * Created by ade on 2016/11/3.
 */
public class MailHandler {

    public static Logger mailHasdlerLogger = Logger.getLogger(MailHandler.class);


    /**
     * 更新文件  删除第一行
     * <p>
     * 更新ipFile
     *
     * @return
     */
    public File refreshProxyFile(String filePath) {
        try {

            File oldFile = new File(filePath);
            List<String> oldFileList = FileUtils.readLines(oldFile, Charset.defaultCharset());
            //移除第一行
            oldFileList.remove(0);
            //删除以前的文件
            oldFile.delete();
            //生成新的文件
            File newFile = new File(filePath);
            for (String str : oldFileList) {
                FileUtils.write(newFile, str, Charset.defaultCharset(), true);
                FileUtils.write(newFile, "\r\n", Charset.defaultCharset(), true);
            }
            return newFile;
        } catch (IOException e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }
    }


    /**
     * 通过msg 获取MailInfo
     *
     * @param msg
     * @return
     */
    public static HashMap<String, Object> getMailInfoMap(MimeMessage msg, StringBuffer content) throws Exception {
        HashMap<String, Object> mailInfoMap = new HashMap<String, Object>();
        String subject = getSubject(msg);
        String from = getFrom(msg);
        String receiveAddress = getReceiveAddress(msg, Message.RecipientType.TO);
        String copyTo = getReceiveAddress(msg, Message.RecipientType.CC);
        String blindCopy = getReceiveAddress(msg, Message.RecipientType.BCC);
        String sentDate = getSentDate(msg, null);
        boolean isSeen = isSeen(msg);
        String priority = getPriority(msg);
        boolean isReplySign = isReplySign(msg);
        String size = msg.getSize() / 1024 + "kb";
        getMailTextContent(msg, content);
        mailInfoMap.put("subject", subject);
        mailInfoMap.put("from", from);
        mailInfoMap.put("receiveAddress", receiveAddress);
        mailInfoMap.put("copyTo", copyTo);
        mailInfoMap.put("blindCopy", blindCopy);
        mailInfoMap.put("sentDate", sentDate);
        mailInfoMap.put("isSeen", isSeen);
        mailInfoMap.put("priority", priority);
        mailInfoMap.put("isReplySign", isReplySign);
        mailInfoMap.put("size", size);
        mailInfoMap.put("content", Jsoup.parse(content.toString()).text());
        return mailInfoMap;
    }

    /**
     * 传入mail对象判断是否能够链接邮箱，如果可以那么就是pop3 否则就是imap方式
     *
     * @param mail
     * @return
     * @throws MessagingException
     */
    public boolean isConnected(Properties props, Mail mail) {
        String[] ipProxyAttr = new String[2];
        try {
            if (getStoreOfImap(props, mail, ipProxyAttr).isConnected()) {
                return true;
            } else if (getStore(props, mail, ipProxyAttr).isConnected()) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 判断代理是否可用
     *
     * @return
     * @throws Exception
     */
    public boolean isProxyIpCanUse(String ip, String port) {
        try {
            Socket socket = null;
            socket = new Socket(new java.net.Proxy(java.net.Proxy.Type.SOCKS, new InetSocketAddress(ip, Integer.parseInt(port))));
            socket.connect(new InetSocketAddress("imap.126.com", Integer.parseInt("143")));
            //设置超时时间2秒，要不然等好久
            socket.setSoTimeout(2000);
            mailHasdlerLogger.info(ip + "代理可用");//可用ip
            return true;
        } catch (IOException e) {
            mailHasdlerLogger.info("异常代理 " + ip + " 不可用异常" + e.getMessage());//异常IP
            return false;
        }
    }

    /**
     * 如果检测有提示: 这四种情况
     * 网易邮箱帐号异常登录提醒
     * 网易邮箱提醒：您邮箱的IMAP服务未开启
     * 网易邮箱提醒：您邮箱的POP3服务未开启
     * 网易邮箱提醒：阻止了一次不安全的收信请求
     * 返回 true 删除成功，返回false表示未删除成功或者未查询到邮件
     *
     * @param messages
     * @return
     */
    public Message[] deleteTheRecentMail(List<String> subList, Message... messages) {
        try {
            //证明可以查询到邮件数据
            if (null != messages && messages.length > 0) {
                MimeMessage message = (MimeMessage) messages[messages.length - 1];//获取到最近的数据
                String strMail = MailUtil.getSubject(message);
                boolean flag = subList.contains(strMail);
                if (null != strMail && flag) {//判断最近的一封邮件主题包含需要删除的邮件
                    //进行删除操作
//                    mailHasdlerLogger.info("要删除的邮件是: " + strMail);
                    message.setFlag(Flags.Flag.DELETED, true);
                    //再次获取看是否删除完成  目前还没有做判断 不管怎么样都直接返回message ,这里有个list arrayList的坑
                    Message[] messages1 = copyOf(messages, messages.length - 1);
                    return messages1;
                } else {
//                    mailHasdlerLogger.info("未删除邮件，邮件标题为: " + strMail);
                    //查询到邮件，但是不包含不安全请求方面的邮件也返回messages
                    return messages;
                }
            } else {
                //证明没有查询到邮件返回
                return messages;
            }
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }
    }


    /**
     * 返回imap方式的store
     *
     * @param mail
     * @param proxyIpAttr
     * @return
     */
    public Store getStoreOfImap(Properties props, Mail mail, String[] proxyIpAttr) {
        // 准备连接服务器的会话信息
        props.setProperty("mail.store.protocol", mail.getProtocol());
        props.setProperty("mail." + mail.getProtocol() + ".host", mail.getHost());
        props.setProperty("mail." + mail.getProtocol() + ".port", mail.getPort());
        props.setProperty("mail." + mail.getProtocol() + ".class", IMAP2Store.class.getName());
        try {
            Session session = Session.getInstance(props);
            session.addProvider(new Provider(Provider.Type.STORE, mail.getProtocol(), IMAP2Store.class.getName(), "Sun Microsystems, Inc.", "1.4.7"));
            Store store = session.getStore(mail.getProtocol());
            store.connect(mail.getUsername(), mail.getPasswd());
            return store;
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }
    }

    /**
     * 获取 store普通pop3
     *
     * @param props
     * @param mail
     * @param proxyIpAttr
     * @return
     */
    public Store getStore(Properties props, Mail mail, String[] proxyIpAttr) {
        // 准备连接服务器的会话信息
        props.setProperty("mail.store.protocol", mail.getProtocol());       // 协议
        props.setProperty("mail." + mail.getProtocol() + ".port", mail.getPort());             // 端口
        props.setProperty("mail." + mail.getProtocol() + ".host", mail.getHost());    // pop3服务器
        try {
            Session session = Session.getInstance(props);
            Store store = session.getStore(mail.getProtocol());
            store.connect(mail.getUsername(), mail.getPasswd());
            return store;
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }
    }

    /**
     * 163 邮箱imap 进行一个特殊的设置
     *
     * @param mail
     * @return
     * @throws MessagingException
     */
    public Message[] getMessagesOfImap(Mail mail, String[] proxyIpAttr) {
        // 准备连接服务器的会话信息
        Properties props = new Properties();
        // 设置会话级别的代理
//        props.setProperty("mail." + mail.getProtocol() + ".socks.host", proxyIpAttr[0]);
//        props.setProperty("mail." + mail.getProtocol() + ".socks.port", proxyIpAttr[1]);
        try {
            Store store = getStoreOfImap(props, mail, proxyIpAttr);
            Folder folder = store.getFolder("INBOX");
            folder.open(Folder.READ_WRITE); //打开收件箱
            return folder.getMessages();
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }
    }

    /**
     * 进行pop3解析
     *
     * @param mail
     * @param proxyIpAttr
     * @return
     * @throws MessagingException
     */
    public Message[] getMessages(Mail mail, String[] proxyIpAttr) throws MessagingException {
        // 准备连接服务器的会话信息
        Properties props = new Properties();
//        props.setProperty("mail." + mail.getProtocol() + ".socks.host", proxyIpAttr[0]);
//        props.setProperty("mail." + mail.getProtocol() + ".socks.port", proxyIpAttr[1]);
        try {
            Store store = getStore(props, mail, proxyIpAttr);
            Folder folder = store.getFolder("INBOX");
            folder.open(Folder.READ_WRITE); //打开收件箱
            return folder.getMessages();
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return null;
        }

    }

    /**
     * 不断更新mailMap中的用户名还有密码
     *
     * @param host
     * @param parmsMailMap
     * @param userInfo
     * @return
     */
    public Map<String, Mail> getMailMapByuserInfo(String host, Map<String, Mail> parmsMailMap, String[] userInfo) {
        Mail mail = parmsMailMap.get(host);
        mail.setUsername(userInfo[0]);
        mail.setPasswd(userInfo[1]);
        parmsMailMap.put(host, mail);
        return parmsMailMap;
    }

    /**
     * 传入邮箱判断是否可以登录，可以登录的126 163邮箱都保存上还有其他的不是126 163的邮箱
     *
     * @param readFile
     * @param saveFile
     * @throws IOException
     */
    public void saveCanConnectedMail(List<String> subList, MailHandler mailHandler, File readFile, File saveFile) throws IOException {
        List<String> emailList = FileUtils.readLines(readFile, Charset.defaultCharset());
        Properties props = new Properties();
        int i = 0;
        Map<String, Mail> mailMap = XpathUtil.getMailByXpath();
        for (String emInfo : emailList) {
            try {
                //对单条email 进行逗号的拆分成一个数组
                String[] userInfo = emInfo.split("--");
                if (2 == userInfo.length) {
                    mailHasdlerLogger.info("解析--------" + i + "-------" + userInfo[0]);
                    String strHost = StringUtil.getHost("imap", userInfo[0]);
                    Mail mail = new Mail();
                    boolean flag = false;
                    Map<String, Mail> returnMap = mailHandler.getMailMapByuserInfo(strHost, mailMap, userInfo);
                    flag = this.isConnected(props, returnMap.get(strHost));
                    if (!flag) { //不能连上
                        strHost = StringUtil.getHost("pop3", userInfo[0]);
                        returnMap = mailHandler.getMailMapByuserInfo(strHost, mailMap, userInfo);
                        flag = this.isConnected(props, returnMap.get(strHost));
                    }
                    if (flag) {//证明能够连接上
                        //这里没有用到，所以就暂时不改了，哪里写userInfo 显然是不对的应该是ipProxyAttr
                        mailHandler.deleteTheRecentMail(subList, mailHandler.getMessageByMail(mail, userInfo));
                        FileUtil.writeFileOfTwoAttr(saveFile, userInfo, Charset.defaultCharset(), true);
                        mailHasdlerLogger.info(userInfo[0] + " : 写入成功");
                    }
                }
                i++;
            } catch (Exception e) {
                i++;
                mailHasdlerLogger.info(e.getMessage());
            }

        }

    }

    /**
     * 传入mail 获取message
     *
     * @param mail
     * @return
     * @throws MessagingException
     */
    public Message[] getMessageByMail(Mail mail, String[] proxyIpAttr) {
        Message[] messages = null;
        try {
            //连接完后进行删除操作
            messages = this.getMessagesOfImap(mail, proxyIpAttr);
            if (null == messages) {
                messages = this.getMessages(mail, proxyIpAttr);
            }
            return messages;
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
            return messages;
        }
    }

    /**
     * 保存数据到kafka
     *
     * @param messages 要保存的数据
     */
    public void excuteMassage(String topicName, KafkaProducer kafkaProducer, Message... messages) {
        Gson gson = new Gson();
        String json = "";
        try {
            if (messages == null || messages.length < 1) {
                throw new MessagingException("未找到要解析的邮件!");
            }
            // 解析所有邮件
            for (int i = 0, count = messages.length; i < count; i++) {
                MimeMessage msg = (MimeMessage) messages[i];
                StringBuffer content = new StringBuffer(30);
                HashMap<String, Object> mailInfoMap = getMailInfoMap(msg, content);
                //这里把map转换为 json
                json = gson.toJson(mailInfoMap);
                kafkaProducer.send(new ProducerRecord(topicName, json.getBytes()));
            }
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
        }
    }

    /**
     * 保存数据到es
     *
     * @param transportClient es的client
     * @param index           要保存到的index名称
     * @param messages        要保存的数据
     */
    public void excuteMassage(TransportClient transportClient, String index, String type, Message... messages) {

        ESUtils esUtils = new ESUtils();
        try {
            if (messages == null || messages.length < 1)
                throw new MessagingException("未找到要解析的邮件!");
            List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
            // 解析所有邮件
            for (int i = 0, count = messages.length; i < count; i++) {
                MimeMessage msg = (MimeMessage) messages[i];
                StringBuffer content = new StringBuffer(30);
                HashMap<String, Object> mailInfoMap = getMailInfoMap(msg, content);
                list.add(mailInfoMap);
            }
            //for循环执行完后调用 es的接口 插入数据
            esUtils.execute(transportClient, index, type, list);
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
        }
    }

    /**
     * 解析并保存数据到电脑上
     *
     * @param messages
     * @throws Exception
     */
    public void excuteMassage(File file, Message... messages) {
        Gson gson = new Gson();
        try {
            if (messages == null || messages.length < 1)
                throw new MessagingException("未找到要解析的邮件!");
            // 解析所有邮件
            for (int i = 0, count = messages.length; i < count; i++) {
                MimeMessage msg = (MimeMessage) messages[i];
                //mailHasdlerLogger.info("------------------解析第" + msg.getMessageNumber() + "封邮件-------------------- ");
                StringBuffer content = new StringBuffer(30);
                HashMap<String, Object> mailInfoMap = getMailInfoMap(msg, content);
                FileUtil.writeMessageToFile(gson, file, mailInfoMap);
            }
        } catch (Exception e) {
            mailHasdlerLogger.info(e.getMessage());
        }
    }


}
